/*
 * Copyright 2014, General Dynamics C4 Systems
 *
 * SPDX-License-Identifier: GPL-2.0-only
 */

#pragma once

#include <basic_types.h>
#include <config.h>
#include <arch/types.h>
#include <linker.h>
#include <sel4/sel4_arch/constants.h>

#define PAGE_BITS seL4_PageBits                             /*Z 12 */
#define LARGE_PAGE_BITS seL4_LargePageBits                  /*Z 21 */
#define L1_CACHE_LINE_SIZE_BITS CTZL(CONFIG_CACHE_LN_SZ)    /*Z 6 */
#define L1_CACHE_LINE_SIZE CONFIG_CACHE_LN_SZ               /*Z 64 */

enum vm_fault_type {
    X86DataFault = seL4_DataFault,  /*Z 0-非取指令导致 */
    X86InstructionFault = seL4_InstructionFault /*Z 1-取指令导致 */
};

typedef word_t vm_fault_type_t;     /*Z 页错误类型 */

enum vm_page_size {
    X86_SmallPage,  /*Z 0。正常页大小 */
    X86_LargePage,  /*Z 1。大页 */
    X64_HugePage    /*Z 2。巨页 */
};
typedef word_t vm_page_size_t;  /*Z 页大小枚举类型 */

enum frameSizeConstants {
    X64SmallPageBits = seL4_PageBits,
    X64LargePageBits = seL4_LargePageBits,
    X64HugePageBits  = seL4_HugePageBits
};

enum vm_page_map_type {
    X86_MappingNone = 0,    /*Z 未映射 */
    X86_MappingVSpace,      /*Z MMU映射 */
#ifdef CONFIG_IOMMU
    X86_MappingIOSpace,     /*Z IOMMU映射 */
#endif
#ifdef CONFIG_VTX
    X86_MappingEPT          /*Z VMX EPT映射(extended page-table) */
#endif
};
typedef word_t vm_page_map_type_t;  /*Z 页映射枚举类型 */
/*Z 根据页大小的枚举类型返回实际页大小(位数) */
/* Any changes to this function need to be replicated in pageBitsForSize_phys.
 */
static inline word_t CONST pageBitsForSize(vm_page_size_t pagesize)
{
    switch (pagesize) {
    case X86_SmallPage:
        return seL4_PageBits;

    case X86_LargePage:
        return seL4_LargePageBits;

    case X64_HugePage:
        return seL4_HugePageBits;

    default:
        fail("Invalid page size");
    }
}

/* This function is a duplicate of pageBitsForSize, needed for calls that occur
 * before the MMU is turned on. Note that any changes to this function need to
 * be replicated in pageBitsForSize.
 */
PHYS_CODE
static inline word_t CONST pageBitsForSize_phys(vm_page_size_t pagesize)
{
    switch (pagesize) {
    case X86_SmallPage:
        return seL4_PageBits;

    case X86_LargePage:
        return seL4_LargePageBits;

    case X64_HugePage:
        return seL4_HugePageBits;

    default:
        fail("Invalid page size");
    }
}

/* Returns the size of CPU's cacheline */
/*Z 通过cpuid指令获取cacheline大小（字节），放入到eax中 */
uint32_t CONST getCacheLineSize(void);
uint32_t CONST getCacheLineSizeBits(void);
/*Z 刷出指针所指内存的各级cache */
/* Flushes a specific memory range from the CPU cache */
static inline void flushCacheLine(volatile void *vaddr)
{   /*Z 0. clflush指令要求的是操作数的内存地址
        1. 冒号后是OUTPUT操作数指示，因此CVARIABLE处是左值（即内存位置）
        2. "+m"约束指定操作数的value在内存里(即汇编指令中不能用clflush (%[vaddr])的形式，因为没有内存间接寻址模式，因此必须有下条dereference)
        3. *vaddr指示value是在vaddr所指向的内存位置，如果去掉*则指示value是在vaddr里

        如果用寄存器传参，则为：
    asm volatile("clflush (%[vaddr])":[vaddr] "+r"((volatile char *)vaddr));
        */
    asm volatile("clflush %[vaddr]" : [vaddr] "+m"(*((volatile char *)vaddr)));
}

void flushCacheRange(void *vaddr, uint32_t size_bits);

/* Disables a variety of prefetchers */
bool_t disablePrefetchers(void);
/*Z 允许普通用户读取性能监测计数器 */
/* Enable user level access to the performance counters */
BOOT_CODE void enablePMCUser(void);

/* Flushes entire CPU Cache */
static inline void x86_wbinvd(void)
{
    asm volatile("wbinvd" ::: "memory");
}

static inline void arch_clean_invalidate_caches(void)
{
    x86_wbinvd();
}
/*Z 与分支预测有关的设置 */
/* Initialize Indirect Branch Restricted Speculation into the mode specified by the build configuration */
bool_t init_ibrs(void);
